<?php
	
	namespace Aspic\File;
	
	use Aspic as A;
	
	/**
	* Do the same as php glob function but with more possibilities
	*/
	class FilesGlob {
		
		const MATCH_TYPE_REGEX = 'regex';
		const MATCH_TYPE_INC_EXTS = 'incExts'; // only given extensions
		const MATCH_TYPE_EXC_EXTS = 'excExts';
		const MATCH_TYPE_FUNC = 'function'; // function ($params, $fileNameWithExt, $filePath)
		
		const SORT_TYPE_NAMES = 'names';
		const SORT_TYPE_DIRS_FIRST = 'dirsFirst';
		
		/*
			PARAMETERS
			----------
			
			recursiveLevels:	Maximum depth level
			matchType:			Validation done on file to define if they are returned or not (set with setMatchType()). See class consts
			matchTypeParams:			
			useDirTree:			True: return multi-dimensions array in which folders are keys
			returnFullPath:		True: return the full path of the file from the first depth level
			sortType:			Define sort type (see class consts)
		    getDirs:            When useDirTree is false, define if dirs should be return or not
		*/
		
		protected $_params;
		
		public function __construct(array $params = array()) {
			$this
			->setParam('recursiveLevels', 0)
			
			->setParam('matchType', null)
			->setParam('matchTypeParams', array())
			
			->setParam('useDirTree', true)
			->setParam('returnFullPath', false)
			
			->setParam('sortType', self::SORT_TYPE_DIRS_FIRST)
					
			->setParam('getDirs', true);
			
		
			foreach($params as $pName => $pValue) {
				$this->setParam($pName, $pValue);
			}
		}
		
		public function setParam($name, $value) {
			$this->_params[$name] = $value;
			
			return $this;
		}
		
		public function setMatchType($matchType, $params) {
			if(
				$matchType == self::MATCH_TYPE_INC_EXTS OR
				$matchType == self::MATCH_TYPE_EXC_EXTS
			) {
				if(!is_array($params)) {
					$params = explode(';', $params);
				}
			
				foreach($params as &$ext) {
					$ext = strtolower($ext);
				}
				unset($ext);
				
			}
		
			$this->setParam('matchType', $matchType);
			$this->setParam('matchTypeParams', $params);
		}
		
		public function getParam($name) {
			if(isset($this->_params[$name])) {
				return $this->_params[$name];
			}
			else {
				return null;
			}
		}
		
		/**
		* Get files from a directory
		*/
		public function find($dir) {
			if(is_dir($dir)) {
				$files = $this->getFiles($dir);
				
				$files = $this->sortFiles($files);
				
				return $files;
			}
			else {
				throw new A\Exception('"'.$dir.'" is not a directory');
			}
		}
		
		protected function getFiles($dir, $level = 0) {
			$pDir = opendir($dir);
			
			$data = array();
			
			while($fn = readdir($pDir)) {
				$fp = $dir.'/'.$fn;
				
				if($this->getParam('returnFullPath')) {
					$sp = $fp; // sp = store path
				}
				else {
					$sp = $fn;
				}
				
				if(!in_array($fn, array('.', '..'))) {
					if(is_file($fp)) {
						if($this->fileMatch($fn,$fp)) {
							$data[] = $sp;
						}
					}
					elseif(is_dir($fp)) {
						if(($level + 1) <= $this->getParam('recursiveLevels') OR $this->getParam('recursiveLevels') == 0) {
							if($this->dirMatch($fn, $fp)) {
								if($this->getParam('useDirTree')) {
									$data[$sp] = $this->getFiles($fp, $level+1);
								}
								elseif($this->getParam('getDirs')) {
//									$data = array_merge($data, $this->getFiles($fp, $level + 1));
									$data[] = $sp;
								}
							}
						}
					}
				}
			}
			
			return $data;
		}
		
		protected function sortFiles($files) {
			if($this->getParam('sortType') == self::SORT_TYPE_DIRS_FIRST) {
				$sortedFiles = array();
				
				foreach($files as $key => $file) {
					if(!is_numeric($key)) {
						$sortedFiles[$key] = $file;
						unset($files[$key]);
					}
				}
				
				$sortedFiles = $sortedFiles + $files;
			}
			
			return $sortedFiles;
		}
		
		/**
		* Determine if file match pre-requisite (params)
		*/
		protected function fileMatch($fileNameWithExt, $filePath) {
			$params = $this->getParam('matchTypeParams');
			$fileExt = strtolower(substr($fileNameWithExt, strrpos($fileNameWithExt, '.') + 1));
		
			if($this->getParam('matchType') == self::MATCH_TYPE_REGEX) {
				return (bool)(preg_match($params, $fileNameWithExt));
			}
			elseif($this->getParam('matchType') == self::MATCH_TYPE_INC_EXTS) {
				return in_array($fileExt, $params);
			}
			elseif($this->getParam('matchType') == self::MATCH_TYPE_EXC_EXTS) {
				return !in_array($fileExt, $params);
			}
			elseif($this->getParam('matchType') == self::MATCH_TYPE_FUNC) {
				return call_user_func($params, $fileNameWithExt, $filePath);
			}
			else {
				return true;
			}
		}
		
		/**
		* Determine if directory match pre-requisite (params)
		*/
		protected function dirMatch($dirName,$dirPath) {
			return true;
		}
		
	}
	
	
	// $gFiles = new FilesGlob();
	// $gFiles->setParam('recursiveLevels',1);
	// $gFiles->setParam('useDirTree',false);
	// $gFiles->setParam('returnFullPath',true);
	// $gFiles->setMatchType(FilesGlob::MATCH_TYPE_INC_EXTS,'php');
	
	// $files = $gFiles->find('.');
	
	// var_dump($files);
	
?>